#include "Tasks.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cerrno>
#include <cassert>
#include <vector>
#include <string>

const int child_process_num = 3;

struct ChildProc
{
    ChildProc(int pid, int write_fd) : _pid(pid), _write_fd(write_fd)
    {
        _proc_name = "proc->" + to_string(_pid) + ":" + to_string(_write_fd);
    }

    int _pid;
    int _write_fd;
    string _proc_name;
};

int SelectBoard()
{
    cout << "#########################" << endl;
    cout << "# 0.wechat     1.chrome #" << endl;
    cout << "# 2.steam      3.quit   #" << endl;
    cout << "#########################" << endl;
    cout << "请选择你将下发的命令: ";

    int command = 0;
    cin >> command;
    return command;
}

void CreatProcess(vector<ChildProc> &cps)
{
    vector<int> wfds;
    for (int i = 0; i < child_process_num; i++)
    {
        // 1.创建管道
        int pipefd[2] = {0};
        int ret = pipe(pipefd);
        if (ret < 0)
        {
            perror("The following error happen:");
        }

        // 父进程当前的写端fd表
        wfds.push_back(pipefd[1]);
        // 父进程写，子进程读（父进程向子进程发送命令）

        // 2.创建多个子进程，一个子进程在父进程中对应一个写端
        int id = fork();
        assert(id >= 0);

        // 子进程
        if (id == 0)
        {
            // 子进程关闭从父进程继承的所有写端!!
            // 错误写法，在当前子进程push写端fd，其它子进程看不到！！！写时拷贝问题
            // wfds.push_back(pipefd[1]);
            // for (auto& wfd : wfds)
            // {
            //     close(wfd);
            //     cout << "关闭fd: " << wfd << endl;
            // }

            for (auto &wfd : wfds)
            {
                close(wfd);
            }

            // close(pipefd[1]);

            // 管道为空时，子进程等待父进程下发命令
            // 子进程接收并执行命令
            while (true)
            {
                int n = 0;
                int cnt = read(pipefd[0], &n, sizeof(int));
                if (cnt > 0)
                {
                    // printf("child process info, pid: %d, writefd_in_parent:%d ", getpid(), tmp);
                    FuncArray[n]();
                    cout << endl;
                }
                else if (cnt == 0)
                {
                    cout << "读取结束，子进程退出"
                         << " pid: " << getpid() << endl;
                    break;
                }
                else
                {
                    exit(1);
                }
            }
            close(pipefd[0]);
            exit(0);
        }

        // 父进程
        // 将子进程(子进程pid和写端fd)管理起来，父进程才方便下发命令
        cps.push_back(ChildProc(id, pipefd[1]));
        close(pipefd[0]);
    }
}

void OrderProcess(vector<ChildProc> &cps)
{
    int num = -1;
    while (true)
    {
        // 用户交互, 下发命令
        int command = SelectBoard();
        if (command == 3)
            break;
        if (command < 0 || command > 2)
            continue;

        // 轮询调用子进程
        num = (num + 1) % cps.size();
        printf("调用了子进程%d号, ", num);
        cout << cps[num]._proc_name << endl;
        // 将命令写入对应子进程的管道中
        write(cps[num]._write_fd, &command, sizeof(command));
        sleep(1);
    }
}

void WaitProcess(vector<ChildProc> &cps)
{
    // 先关闭父进程的所有写端，根据管道的特性，每个写端对应的子进程退出
    // 随后，父进程要回收所有的子进程
    //  for(auto& cp:cps)
    //  {
    //      close(cp._write_fd);
    //  }
    //  for(auto& cp:cps)
    //  {
    //      waitpid(cp._pid,nullptr,0);
    //  }

    for (auto &cp : cps)
    {
        close(cp._write_fd);
        waitpid(cp._pid, nullptr, 0);
    }
}

int main()
{
    vector<ChildProc> child_processes;

    // 1.创建子进程
    CreatProcess(child_processes);

    // 2.父进程下发命令(用户交互式)
    OrderProcess(child_processes);

    // 3.进程退出
    WaitProcess(child_processes);
    cout << "子进程已全部成功退出，并被回收！" << endl;

    return 0;
}

